import 'dart:convert';
import 'package:dio/dio.dart';
import 'package:dio_cookie_manager/dio_cookie_manager.dart';
import 'package:cookie_jar/cookie_jar.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_smart_heating/common/app.dart';
import 'package:flutter_smart_heating/config/config.dart';
import 'package:flutter_smart_heating/service/auth_service.dart';
import 'package:get/get.dart' hide Response, FormData, MultipartFile;
import '../ui/ui.dart';
import 'local_storage.dart';

class Http {
  final Dio dio = Dio();
  static bool debugMode = false;
  final CookieJar cookieJar = CookieJar();
  Http._() {
    dio.options.contentType = "application/x-www-form-urlencoded";
    dio.options.baseUrl = Config.server;
    dio.options.connectTimeout =
        const Duration(seconds: Config.httpRequestTimeout);
    dio.options.receiveTimeout =
        const Duration(seconds: Config.httpRequestTimeout);
    dio.interceptors.add(HttpInterceptor());
    dio.interceptors.add(CookieManager(cookieJar));
    cookieJar.loadForRequest(Uri.parse(Config.server));
    if (debugMode) {
      dio.interceptors
          .add(LogInterceptor(responseBody: true, requestBody: true));
    }
  }
  static final Http instance = Http._();

  Map<String, dynamic> sign(Map<String, dynamic> form) {
    Map<String, dynamic> data = Map.from(form);
    data['timestamp'] = DateTime.now().millisecondsSinceEpoch / 1000;
    List<String> oldKeys = data.keys.toList();
    oldKeys.sort((a, b) {
      List<int> al = a.codeUnits;
      List<int> bl = b.codeUnits;
      for (int i = 0; i < al.length; i++) {
        if (bl.length <= i) return 1;
        if (al[i] > bl[i]) {
          return 1;
        } else if (al[i] < bl[i]) {
          return -1;
        }
      }
      return 0;
    });
    String str = '';
    for (int i = 0; i < oldKeys.length; i++) {
      String field = oldKeys[i];
      var value = data[field];
      if (field != 'sign') {
        if (value.runtimeType.toString().contains("List") ||
            value.runtimeType.toString().contains("Map")) {
          value = jsonEncode(value);
        }
        str += '$field$value';
      }
    }
    str += Config.key + str.replaceAll(RegExp(r"\s+"), '') + Config.key;

    data['sign'] = App.md5(str);
    return data;
  }

  static String get deviceType {
    var platform = 'mobile';
    if (GetPlatform.isAndroid) {
      platform = 'android';
    } else if (GetPlatform.isIOS) {
      platform = 'iphone';
    } else if (GetPlatform.isMacOS) {
      platform = 'mac';
    } else if (GetPlatform.isWindows) {
      platform = 'windows';
    } else if (GetPlatform.isDesktop) {
      platform = 'pc';
    }
    return platform;
  }

  Future<ResponseModel> post(
    String url, {
    dynamic data,
    bool needLoading = false,
    bool needLogin = false,
    CancelToken? cancelToken,
    Function(int, int)? onSendProgress,
    Function(int, int)? onReceiveProgress,
  }) async {
    if (needLogin) {
      var token = LocalStorage.instance.getItem('user.token');
      if (token == null || token == '') {
        App.push('/login');
        throw Exception('token is null');
      }
    }
    if (needLoading) {
      Ui.showLoading();
    }
    debugPrint('====================http.start====================');
    debugPrint('接口地址：$url');
    debugPrint('请求参数：$data');
    ResponseModel result = ResponseModel();
    try {
      Response response = await dio.post(
        url,
        data: data.runtimeType.toString().contains('Map') ? sign(data) : data,
        cancelToken: cancelToken,
        onSendProgress: onSendProgress,
        onReceiveProgress: onReceiveProgress,
      );
      result = ResponseModel.fromJson(response.data);
    } on DioException catch (e) {
      debugPrint(e.message);
      result = ResponseModel(code: 500, msg: '网络请求失败');
    }
    if (needLoading) {
      Ui.hideLoading();
    }
    debugPrint('响应结果：${result.toJson()}');
    debugPrint('====================http.end======================');
    return result;
  }

  /// 取消网络请求
  abort({CancelToken? token}) {
    token?.cancel("cancelled");
  }

  ///文件上传
  Future<ResponseModel> upload(
    String url, {
    dynamic data,
    required String filePath,
    String fieldName = 'file',
    bool needLoading = false,
    bool needLogin = false,
    CancelToken? cancelToken,
    Function(int, int)? onSendProgress,
    Function(int, int)? onReceiveProgress,
  }) async {
    ///截取文件名
    String name =
        filePath.substring(filePath.lastIndexOf("/") + 1, filePath.length);
    Map<String, dynamic> map = {
      fieldName: await MultipartFile.fromFile(filePath, filename: name)
    };
    if (data != null) {
      map.addAll(data);
    }
    FormData formData = FormData.fromMap(map);
    return await post(
      url,
      data: formData,
      needLoading: needLoading,
      needLogin: needLogin,
      onSendProgress: onSendProgress,
      onReceiveProgress: onReceiveProgress,
      cancelToken: cancelToken,
    );
  }

  static String genarateIdentifier(String str) {
    var timestamp =
        DateTime.now().millisecondsSinceEpoch.toString().substring(0, 10);
    var string = App.md5('${Config.appKey}$timestamp${Http.deviceType}$str');
    return '$string$timestamp';
  }
}

/// 拦截器
class HttpInterceptor extends Interceptor {
  @override
  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
    var token = LocalStorage.instance.getItem<String>('user.token');
    options.headers["XX-App-Version"] = Config.appVersion;
    options.headers["XX-Api-Version"] = Config.apiVersion;
    options.headers["XX-Wxapp-AppId"] = "";
    try {
      options.headers["XX-Substation-Id"] = AuthService.instance.substationId;
      // ignore: empty_catches
    } catch (e) {}
    options.headers["User-Agent"] =
        "Flutter/3.10.0 LiaoJianTongApp/${Config.appVersion} for ${Http.deviceType} ";
    options.headers["XX-Device-Type"] = Http.deviceType;
    options.headers["XX-Token"] = token;
    options.headers["Accept-Language"] = Get.locale;
    options.headers["X-Requested-With"] = 'xmlhttprequest';
    options.headers["Content-Type"] = 'application/json';
    options.headers['XX-Identifier'] =
        Http.genarateIdentifier(options.uri.path);
    handler.next(options);
  }

  @override
  void onResponse(Response response, ResponseInterceptorHandler handler) {
    super.onResponse(response, handler);
    var data = ResponseModel.fromJson(response.data);

    /// 10001为登录失效，登录状态下移除token
    if (data.code == 10001 &&
        LocalStorage.instance.getItem('user.token') != null) {
      AuthService.instance.logout();
      App.push('/login', redirect: true);
    }
  }
}

/// 接口返回结果
class ResponseModel {
  int? code;
  String? msg;
  dynamic data;

  ResponseModel({this.code, this.msg, this.data});

  ResponseModel.fromJson(Map<String, dynamic> json) {
    code = json['code'];
    msg = json['msg'];
    data = json['data'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> json = {};
    json['code'] = code;
    json['msg'] = msg;
    json['data'] = data;
    return json;
  }
}
